home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Visual Database / Visual BASIC 5.0 (Ent. Edition) / Vb5ent Extractor.EXE / VB / SAMPLES / ENTRPRIS / APE / AEQUEUE / MODQUEUE.BAS < prev    next >
Encoding:
BASIC Source File  |  1996-12-23  |  34.5 KB  |  715 lines

  1. Attribute VB_Name = "modQueueMgr"
  2. Option Explicit
  3. '-------------------------------------------------------------------------
  4. 'The project is the QueueMgr component of the Application Performance Explorer
  5. 'The QueueManager receives Service Requests from Client applications and
  6. 'places the requests in a Queue.  When it receives a request it passes
  7. 'a received callback object to the Expediter if needed.  Workers poll the
  8. 'QueueMgr taking Service Requests and accomplishing the service.  When
  9. 'the Worker takes a Service request it is removed from the Queue.
  10. 'The Queue Manager creates the Worker(s), the Logger, and the Expediter
  11. '
  12. 'Key Files:
  13. '   frmQueue.frm    Is the only and main form of the app
  14. '   clsPosFm.cls    Is a tool to save the forms position to the registry
  15. '   clsServc.cls    Is a class used to store Service Request Data
  16. '   clsWorkr.cls    Is a class used to store a Worker object and its related
  17. '                   data
  18. '   QueueMgr.cls    Is a creatable multi-use class that provides the
  19. '                   OLE interface for the APE Manager to call
  20. '   clsQueDl.cls    Is a non-creatable public class that is instanciated and
  21. '                   passed to the Workers and expediter for them to call
  22. '   Queue.cls       Is a creatable multi-use class that provides the OLE
  23. '                   interface for client applications to add service
  24. '                   requests to the Queue
  25. '-------------------------------------------------------------------------
  26.  
  27. 'Declarations
  28. Declare Function GetTickCount Lib "kernel32" () As Long
  29.  
  30. 'U/I Caption ResourceString keys
  31. Public Const giFORM_CAPTI0N As Integer = 101
  32. Public Const giCURRENT_QUEUE_CAPTION As Integer = 102
  33. Public Const giPEAK_QUEUE_CAPTION As Integer = 103
  34. Public Const giTOTAL_CALL_CAPTION As Integer = 104
  35. Public Const giWORKER_COUNT_CAPTION As Integer = 105
  36.  
  37. 'Constants
  38. Public Const gbSHOW_FORM_DEFAULT As Boolean = False
  39. Public Const gbLOG_DEFAULT As Boolean = False
  40. Public Const gsPROTOCOL_DEFAULT As String = "ncacn_ip_tcp"
  41. Public Const glAUTHENTICATION_DEFAULT As Long = 1
  42. Public Const giWORKER_QUANTITY_DEFAULT As Integer = 1
  43. Public Const gbWORKER_EARLYBIND_DEFAULT As Integer = True
  44. Public Const gbPERSISTENT_QUEUE_DEFAULT As Boolean = False
  45. Public Const glMAX_QUEUE_SIZE_DEFAULT As Long = 20000   'This was chosen as the ideal MaxQueue size on
  46.                                                         'on a Pentium 100 with 32 meg, running NT4
  47.                                                         'This allows the queue to get large enough for
  48.                                                         'the user to see a performance hit, but not so
  49.                                                         'large that recovery is difficult
  50. Public Const giERROR_THRESHOLD As Integer = 32700
  51. Public Const glMAX_ID As Long = 2147483647
  52. Public Const giMAX_WORKERS As Integer = 30
  53. Public Const giMAX_ALLOWED_RETRIES  As Integer = 500
  54. Public Const giRETRY_WAIT_MIN  As Integer = 500       'Retry Wait is measure in DoEvent cycles
  55. Public Const giRETRY_WAIT_MAX  As Integer = 2500
  56. Public Const giRESULT_ARRAY_REDIM_CHUNK_SIZE = 20
  57. Public Const giRESULT_ARRAY_MAX_SIZE = 200
  58.  
  59. Public Const giRACREG_ERROR_CODE_OFFSET = 200               'Add offset to racreg32 error codes
  60.                                                             'to make corresponding resource string key
  61.  
  62. 'Status codes for Status property of clsService
  63. Public Const giCLIENT_IS_ADDING  As Integer = 0     'Client is currently in the Add method for the
  64.                                                     'respective Service reaquest.  The request should
  65.                                                     'not be delegated yet.
  66. Public Const giWAITING_FOR_WORKER As Integer = 1    'Service request is ready to be taken by worker
  67. Public Const giDELEGATED_TO_WORKER  As Integer = 2  'Worker is processing this service request
  68. Public Const giHAVE_SERVICE_RESULTS As Integer = 3  'Worker has returned results for this Service
  69.                                                     'request.  It is ready to be taken by Expediter
  70.  
  71. 'User Defined Errors which also serve as string
  72. 'resource indexes
  73. Public Const giQUEUE_MGR_IS_BUSY As Integer = 32749
  74. Public Const giFIRST_GET_WITHEVENTS_OBJECT As Integer = 32763
  75. Public Const giNO_WORKERS_CREATED As Integer = 32764
  76. Public Const giINVALID_PARAMETER As Integer = 32765
  77. Public Const giINVALID_CALLBACK As Integer = 32766
  78. Public Const giCOULD_NOT_CREATE_EXPEDITER As Integer = 32762
  79. Public Const giCONNECTION_SETTING_FAILED As Integer = 32750     'An error was returned by RacReg32
  80.  
  81. 'String resourse strings for logging messages
  82. Public Const giQUEUE_NAME As Integer = 2
  83. Public Const giADD_RECEIVED As Integer = 3
  84. Public Const giGETREQUEST_RECEIVED_NEW_SERVICE As Integer = 4
  85. Public Const giGETREQUEST_RECEIVED_RETURNED_RESULTS As Integer = 5
  86. Public Const giGETRESULTS_RECEIVED_RETURNED_RESULTS As Integer = 6
  87.  
  88. Public Const giSTOP_TEST_RECEIVED As Integer = 10
  89. Public Const giCALL_REJECTED_RETRY As Integer = 11
  90. Public Const giUSING_NO_AUTHENTICATION As Integer = 12
  91. Public Const giONLY_N_WORKERS_CREATED As Integer = 13
  92. Public Const giCOULD_NOT_CREATE_WORKER_ON_MACHINE As Integer = 14
  93. Public Const giALL_WORKERS_CREATED As Integer = 15
  94. Public Const giCOULD_NOT_CREATE_LOCAL_WORKER As Integer = 16
  95. Public Const giERROR_PREFIX As Integer = 17
  96.  
  97. Public Const giFONT_CHARSET_INDEX As Integer = 30
  98. Public Const giFONT_NAME_INDEX As Integer = 31
  99. Public Const giFONT_SIZE_INDEX  As Integer = 32
  100.  
  101. 'Global variables
  102. Public glMaxQueueSize As Long  'Maximum allowed size of gcQueue
  103. Public glLastID As Long        'Last Service ID used; for generating a new one
  104. Public glAddCallCount As Long  'Total calls made to Queue.Add
  105. Public glPeakQueueSize As Long 'Largest size of the collection of Service requests
  106. Public gbLog As Boolean        'If True log QueueMgr Events
  107. Public goExpediter As aeexpediter.Expediter  'Expediter class object
  108. Public gcQueue As Collection                 'Collection of clsService class objects
  109.                                              'which contain a data structure for holding
  110.                                              'Service request.
  111. Public gcWorkers As Collection               'Collection of clsWorker class objects
  112. Public gcWorkerMachines As Collection        'Collection of clsWorkerMachines objects used
  113.                                              'keep track of how many worker objects are on
  114.                                              'each remote worker machine.
  115. Public goLogger As aelogger.Logger           'Logger object
  116.                                              
  117. Public gbShow As Boolean                     'If True show frmQueueMgr
  118. Public glInstances As Long                   'Count of number of instances
  119.                                              'of this class
  120. Public giWorkerCount As Integer              'Number of Worker instanciated, This can be different
  121.                                              'than gcWorkers.Count if a Worker in the collection
  122.                                              'is marked for removal it will not be included in giWorkerCount
  123. Public glLastKeyUsed As Long                 'Last key used to add a worker to gcWorkers
  124.                                              'It is necessary to use this because a the
  125.                                              'giWorkerCount can be decreased but the Worker
  126.                                              'not actually removed until it calls back after
  127.                                              'completing a Service request.  During this time
  128.                                              'WorkerQuantity can be called again to increase
  129.                                              'the Worker count.  Therefore, giWorkerCount is
  130.                                              'not reliable for generating unique keys
  131. Public gbLogWorkers As Boolean      'Flag to track status of
  132.                                     'Worker property Log
  133. Public gbPersistentServices As Boolean      'Flag keeps track of Worker
  134.                                             'property PersistentServices
  135.                                             'If true Workers keep reference to
  136.                                             'all Service objects used else they
  137.                                             'drop references after each use.
  138. Public gbEarlyBindServices As Boolean       'Flag to track status of
  139.                                             'Worker property EarlyBound
  140. Public gbShowExpediter As Boolean   'Stores current Expediter property Show
  141. Public gbLogExpediter As Boolean    'Stores current Expediter property Log
  142. Public gbStopTest As Boolean        'Stop Test flag, checked by many procedures
  143.                                     'that will discontinue their processes if true
  144. Public gbBusyAdding As Boolean      'If true, in Queue.Add method
  145. Public gbBusyGetServiceRequest As Boolean   'If true, in clsQueueDelegator.GetServiceRequest method
  146. Public gbBusyGetServiceResults As Boolean   'If true, in clsQueueDelegator.GetServiceResults method
  147. Public gbUnloading As Boolean               'Flag used by Class_terminate
  148. Public gbHaveServiceResults As Boolean      'If true, there are Service Request results to return
  149.                                             'to the Expediter when it polls
  150. Public gsProtocol As String                 'Protocol sequence to use when connecting to Workers
  151. Public glAuthentication As Long             'Authentication level to use when connecting to Workers
  152. Public gbUseDCOM As Boolean                 'If true use DCOM to create workers instead of Remote Automation
  153. Public gbFailedToCreateExpediter As Boolean
  154.  
  155. Sub Main()
  156. End Sub
  157.  
  158. Public Sub CountInitialize()
  159.     '-------------------------------------------------------------------------
  160.     'Purpose:   Keep track of number instances of QueueMgr and Queue
  161.     '           To be called by a public creatable class in its initialize
  162.     '           event. To keep track of how many public creatable objects
  163.     '           are initialized.  Initialize the QueueMgr application if
  164.     '           this is the first time it is called.
  165.     'Effects:
  166.     '           If this is the first instanciation
  167.     '           Put the QueueMgr in a "Ready" state.  Load expediter, and Workers
  168.     '           Set default properties, Show form and load logger if necessary.
  169.     '   [glInstances]
  170.     '           increments by one
  171.     '-------------------------------------------------------------------------
  172.     Dim i As Integer
  173.     Dim oWork As clsWorker                   'Object storing Workers and related informantion
  174.     Dim oService As clsService               'Object storing service requests and results
  175.     Dim oWorkerMachine As clsWorkerMachines  'Object that stores how many
  176.                                              'Workers are on what machines
  177.     Dim sProgID As String           'ProgID trying to be created
  178.                                     'used for error handling
  179.     Dim sReturn As String           'Return of SetWorkersOnMachine function
  180.     Dim bCreatingExpediter As Boolean
  181.     
  182.     On Error GoTo CountInitializeError
  183.     
  184.     glInstances = glInstances + 1
  185.     If glInstances = 1 Then
  186.         App.OleServerBusyRaiseError = True
  187.         App.OleServerBusyTimeout = 10000
  188.         'Set default property values
  189.         gbShow = gbSHOW_FORM_DEFAULT
  190.         gbLog = gbLOG_DEFAULT
  191.         gsProtocol = gsPROTOCOL_DEFAULT
  192.         glAuthentication = glAUTHENTICATION_DEFAULT
  193.         gbEarlyBindServices = gbWORKER_EARLYBIND_DEFAULT
  194.         glMaxQueueSize = glMAX_QUEUE_SIZE_DEFAULT
  195.         'Create Logger class object early so
  196.         'potential errors could be logged
  197.         sProgID = "AELogger.Logger"
  198.         If gbLog Then Set goLogger = New aelogger.Logger
  199.         'gbPersistentQueue = gbPERSISTENT_QUEUE_DEFAULT
  200.         'Create Expediter class object
  201.         sProgID = "AEExpediter.Expediter"
  202.         bCreatingExpediter = True
  203.         Set goExpediter = New aeexpediter.Expediter
  204.         Set goExpediter.QueueMgrRef = New clsQueueDelegator
  205.         bCreatingExpediter = False
  206.         'Load frmQueueMgr because it has a timer
  207.         Load frmQueueMgr
  208.         'Create collection objects
  209.         Set gcWorkers = New Collection
  210.         Set gcQueue = New Collection
  211.         Set gcWorkerMachines = New Collection
  212.         'Add an item to represent number of workers on the local machine
  213.         Set oWorkerMachine = New clsWorkerMachines
  214.         gcWorkerMachines.Add oWorkerMachine
  215.         'Load the default amount of workers and add
  216.         'them to the gcWorkers Collection
  217.         sReturn = SetWorkersOnMachine(False, "", giWORKER_QUANTITY_DEFAULT)
  218.         
  219.         'Only show the form if gbShow is true
  220.         If gbShow Then
  221.             frmQueueMgr.Show
  222.             With frmQueueMgr
  223.                 .lblCount.Caption = 0
  224.                 .lblPeak.Caption = 0
  225.                 .lblQueue.Caption = 0
  226.                 .lblWorkerCount.Caption = gcWorkers.Count
  227.                 .lblCount.Refresh
  228.                 .lblPeak.Refresh
  229.                 .lblQueue.Refresh
  230.                 .lblWorkerCount.Refresh
  231.             End With
  232.         End If
  233.         gbUnloading = False
  234.         'call start test in the  Expediter so it
  235.         'will start polling the QueueMgr
  236.         goExpediter.StartTest
  237.     End If
  238.     Exit Sub
  239. CountInitializeError:
  240.     Select Case Err.Number
  241.         Case ERR_CANT_FIND_KEY_IN_REGISTRY
  242.             'AEInstancer.Instancer is a work around for error
  243.             '-2147221166 which occurrs every time a client
  244.             'object creates an instance of a remote server,
  245.             'destroys it, registers it local, and tries to
  246.             'create a local instance.  The client can not
  247.             'create an object registered locally after it created
  248.             'an instance while it was registered remotely
  249.             'until it shuts down and restarts.  Therefore,
  250.             'it works to call another process to create the
  251.             'local instance and pass it back.
  252.             Dim oInstancer As AEInstancer.Instancer
  253.             Set oInstancer = New AEInstancer.Instancer
  254.             Select Case sProgID
  255.                 Case "AELogger.Logger"
  256.                     Set goLogger = oInstancer.Object("AELogger.Logger")
  257.                 Case "AEExpediter.Expediter"
  258.                     Set goExpediter = oInstancer.Object("AEExpediter.Expediter")
  259.             End Select
  260.             Set oInstancer = Nothing
  261.             Resume Next
  262.         Case Else
  263.             If bCreatingExpediter Then gbFailedToCreateExpediter = True
  264.             LogError Err, 0
  265.             Resume Next
  266.     End Select
  267. End Sub
  268.  
  269. Public Sub CountTerminate()
  270.     '-------------------------------------------------------------------------
  271.     'Purpose:   Keep track of number instances of QueueMgr and Queue
  272.     '           To be called by a public creatable class in its terminate
  273.     '           event. To keep track of how many public creatable objects
  274.     '           are initialized.  Terminate the QueueMgr application if
  275.     '           this is the last time called.
  276.     'Effects:
  277.     '           Unload all objects, and unload form so that this application
  278.     '           will close
  279.     '   [glInstances]
  280.     '           decrements by one
  281.     '-------------------------------------------------------------------------
  282.     Dim oWorker As clsWorker
  283.     On Error GoTo Class_TerminateError
  284.     glInstances = glInstances - 1
  285.     'If already started unloading don't check
  286.     'instance count again
  287.     If Not gbUnloading Then
  288.         If glInstances = 0 Then
  289.             gbUnloading = True
  290.             goExpediter.StopTest
  291.             For Each oWorker In gcWorkers
  292.                 oWorker.Worker.ShutDown
  293.             Next
  294.             For Each oWorker In gcWorkers
  295.                 Set oWorker.Worker = Nothing
  296.                 Set oWorker = Nothing
  297.             Next
  298.             Set goLogger = Nothing
  299.             Set gcWorkers = Nothing
  300.             giWorkerCount = 0
  301.             Set gcWorkerMachines = Nothing
  302.             Set goExpediter = Nothing
  303.             Set gcQueue = Nothing
  304.             Unload frmQueueMgr
  305.         End If
  306.     End If
  307.     Exit Sub
  308. Class_TerminateError:
  309.     LogError Err, 0
  310.     Resume Next
  311. End Sub
  312.  
  313. Public Sub LogEvent(intMessage As Integer, lServiceID As Long)
  314.     '-------------------------------------------------------------------------
  315.     'Purpose:   Receives Message key which is used to look
  316.     '           up a resource string.  The logrecord is sent to the
  317.     '           Logger object if gbLog is true
  318.     'In:        [intMessage]
  319.     '               A valid Resource string key for the message to be logged
  320.     '           [lServiceID]
  321.     '               Service Request ID to be logged
  322.     'Assumption:
  323.     '           If gbLog is true then goLogger is a valid reference to
  324.     '           AELogger.Logger class object
  325.     '-------------------------------------------------------------------------
  326.     On Error GoTo LogEventError
  327.     If gbLog And Not gbStopTest Then
  328.         goLogger.Record LoadResString(giQUEUE_NAME), lServiceID, LoadResString(intMessage), GetTickCount()
  329.     End If
  330.     'If the form is visible display log on form
  331.     #If ccShowList Then
  332.         DisplayString CStr(lServiceID) & gsSEPERATOR & LoadResString(intMessage)
  333.     #End If
  334.     Exit Sub
  335. LogEventError:
  336.     LogError Err, lServiceID
  337.     Exit Sub
  338. End Sub
  339.  
  340. Public Sub LogText(sMsg As String, lServiceID As Long)
  341.     '-------------------------------------------------------------------------
  342.     'Purpose:   Passes that passed string and ServiceID as a log record
  343.     '           to the logger
  344.     'In:        [sMsg]
  345.     '               String to be logged
  346.     '           [lServiceID]
  347.     '               Service Request ID to be logged
  348.     'Assumption:
  349.     '           If gbLog is true then goLogger is a valid reference to
  350.     '           AELogger.Logger class object
  351.     '-------------------------------------------------------------------------
  352.     On Error GoTo LogTextError
  353.     If gbLog And Not gbStopTest Then
  354.         goLogger.Record LoadResString(giQUEUE_NAME), lServiceID, sMsg, GetTickCount()
  355.     End If
  356.     'If the form is visible display log on form
  357.     #If ccShowList Then
  358.         DisplayString CStr(lServiceID) & gsSEPERATOR & sMsg
  359.     #End If
  360.     Exit Sub
  361. LogTextError:
  362.     LogError Err, lServiceID
  363.     Exit Sub
  364. End Sub
  365.  
  366. Public Sub LogError(ByVal oErr As ErrObject, lServiceID As Long)
  367.     '-------------------------------------------------------------------------
  368.     'Purpose:   Display error description on forms Status box if the form is
  369.     '           visible; log error if logging is on
  370.     'In:        [oErr]
  371.     '               Valid error object
  372.     '           [lServiceID]
  373.     '               Service Request ID logged with the error message
  374.     'Assumption:
  375.     '           If gbShow is true the form is loaded and visible
  376.     '           If gbLog is true the goLogger is a valid AELogger.Logger class
  377.     '               object
  378.     '-------------------------------------------------------------------------
  379.     
  380.     Dim s As String
  381.     s = LoadResString(giERROR_PREFIX) & Str$(oErr.Number) & gsSEPERATOR & oErr.Source & gsSEPERATOR & oErr.Description
  382.     #If ccShowList Then
  383.         If Not gbShow Then
  384.             frmQueueMgr.Show
  385.             gbShow = True
  386.         End If
  387.         DisplayString s
  388.     #Else
  389.         If oErr.Number <> 0 Then DisplayStatus oErr.Description
  390.     #End If
  391.     If gbLog And glInstances <> 0 Then
  392.         goLogger.Record LoadResString(giQUEUE_NAME), lServiceID, s, GetTickCount()
  393.     End If
  394. End Sub
  395.  
  396. Sub DisplayStatus(s As String)
  397.     '-------------------------------------------------------------------------
  398.     'Purpose:   If gbShow is true, displays passed string on forms status box
  399.     'Assumes:   If gbShow is true, form is loaded and visible
  400.     '-------------------------------------------------------------------------
  401.     If gbShow Then frmQueueMgr.lblStatus = s
  402. End Sub
  403.  
  404. Sub DisplayString(sText As String)
  405.     '-------------------------------------------------------------------------
  406.     'Purpose:   Adds the passed text to to the list box.  Only used if conditional
  407.     '           compile ccShowList is true.
  408.     'Assumes:   If gbShow is true, form is visible
  409.     '           If ccShowList is true, lstLog is visible and positioned
  410.     '-------------------------------------------------------------------------
  411.     'Controls the length of the list box
  412.     'and sets ListIndex
  413.     #If ccShowList Then
  414.         Dim lstLog As ListBox
  415.         If gbShow Then
  416.             Set lstLog = frmQueueMgr.lstLog
  417.             If lstLog.ListCount = giLIST_BOX_MAX Then lstLog.Clear
  418.             lstLog.AddItem sText, 0
  419.             DoEvents
  420.         End If
  421.     #End If
  422. End Sub
  423.  
  424. Function gFormatPath(sPath As String) As String
  425.     '-------------------------------------------------------------------------
  426.     'Purpose:   Assures that the passed path has a "\" at the end of it
  427.     'IN:
  428.     '   [sPath]
  429.     '           a valid path name
  430.     'Return:    the same path with a "\" on the end if it did not already
  431.     '           have one.
  432.     '-------------------------------------------------------------------------
  433.     If Right$(sPath, 1) <> "\" Then
  434.         gFormatPath = sPath & "\"
  435.     Else
  436.         gFormatPath = sPath
  437.     End If
  438. End Function
  439.  
  440. Sub StopQueue()
  441.     '-------------------------------------------------------------------------
  442.     'Purpose:   Stops processing of Service Requests by deleging the pending
  443.     '           requests
  444.     'Assumes:   Assumes that clients have already stopped posting new requests
  445.     '-------------------------------------------------------------------------
  446.     LogEvent giSTOP_TEST_RECEIVED, 0
  447.     DisplayStatus LoadResString(giSTOP_TEST_RECEIVED)
  448.     Set gcQueue = Nothing
  449.     Set gcQueue = New Collection
  450. End Sub
  451.  
  452. Public Function SetWorkersOnMachine(bRemote As Boolean, sMachineName As String, lQuantityOnMachine As Long) As String
  453.     '-------------------------------------------------------------------------
  454.     'Purpose:   Sets the quantity of instanciated Workers on a particular machine
  455.     'IN:
  456.     '   [bRemote]
  457.     '           If true adjust number of workers on a remote machine; else,
  458.     '           adjust the number on the local machine.
  459.     '   [sMachineName]
  460.     '           Name of machine to adjust the level of instanciated Workers
  461.     '   [lQuantityOnMachine]
  462.     '           Number of Instantiated Workers that should be on specified
  463.     '           machine.
  464.     'Return:    Discription of Errors that should be displayed to user
  465.     'Effects:
  466.     '   [gcWorkers]
  467.     '           The number of Workers in this collection will be adjusted
  468.     '   [gcWorkerMachines]
  469.     '           An item may be added or removed or edited
  470.     '-------------------------------------------------------------------------
  471.     Dim oRacReg As RacReg.RegClass          'Object to set automation connection settings
  472.     Dim oWorkerMachine As clsWorkerMachines 'Object that stores how many workers are on
  473.                                             'a machine, retrieved from global collection
  474.     Dim lWorkerToRemove As Long             'ID of Worker found to remove
  475.     Dim oWork As clsWorker                  'clsWorker object that hold reference to a Worker
  476.                                             'and information related to it
  477.     Dim oWorkerProvider As AEWorkerProvider.WorkerProvider  'Server that can be instanciated on remote
  478.                                                             'machines to provide Worker objects
  479.     Dim lAdd As Long                        'New ID for New Worker
  480.     Dim sErrors As String                   'Discription of Errors that will be returned
  481.     Dim bAddingWorker As Boolean            'If true, adding and configuring worker
  482.                                             'used by error handling
  483.     Dim iRetry As Integer                   'Error retry counter
  484.     Dim iResult As Integer                  'RacReg error code
  485.     
  486.     On Error GoTo SetWorkersOnMachineError
  487.     
  488.     'Validate lQuantityOnMachine
  489.     If lQuantityOnMachine < 0 Then lQuantityOnMachine = 0
  490.     
  491.     'Set registry for local or remote machine name
  492.     Set oRacReg = New RacReg.RegClass
  493.     If bRemote Then
  494.         If gbUseDCOM Then
  495.             iResult = oRacReg.SetDCOMServerSettings(True, "AEWorkerProvider.WorkerProvider", , sMachineName)
  496.         Else
  497.             iResult = oRacReg.SetAutoServerSettings(True, "AEWorkerProvider.WorkerProvider", , sMachineName, gsProtocol, glAuthentication)
  498.         End If
  499.     Else
  500.         'Make sure the Machine name string is zero length
  501.         sMachineName = ""
  502.         'Make sure AEWorker.Worker is registered for local instanciation
  503.         'Because Clients may have been run on this machine and may have
  504.         'left the connection settings remote if they did not unload properly
  505.         iResult = oRacReg.SetAutoServerSettings(False, "AEWorker.Worker")
  506.         
  507.     End If
  508.     If iResult <> 0 Then GoTo SetWorkersOnMachine_RacRegError
  509.     
  510.     'Get the clsWorkerMachines object to store information in
  511.     If Not bRemote Then
  512.         'it is definitely the first item in the collection
  513.         Set oWorkerMachine = gcWorkerMachines.Item(1)
  514.     Else
  515.         'if it is in the collection it is stored by a key
  516.         'equaling the machine name
  517.         'If error equals ERR_INVALID_PROCEDURE_CALL there
  518.         'are no Workers on specified machine and no clsWorkerMachines
  519.         'class object to represent them
  520.         On Error Resume Next
  521.         Set oWorkerMachine = gcWorkerMachines.Item(sMachineName)
  522.         If Err.Number = ERR_INVALID_PROCEDURE_CALL Then
  523.             On Error GoTo SetWorkersOnMachineError
  524.             'Don't create a new clsWorkerMachine object of
  525.             'lQuantityOnMachine is zero
  526.             If lQuantityOnMachine <= 0 Then Exit Function
  527.             Set oWorkerMachine = New clsWorkerMachines
  528.             'If an error occurs creating WorkerProvider the current machine name
  529.             'can not be used.  Treat error as if a Worker can not be created on
  530.             'paticular machine.
  531.             bAddingWorker = True
  532.             Set oWorkerMachine.WorkerProvider = New AEWorkerProvider.WorkerProvider
  533.             bAddingWorker = False
  534.             gcWorkerMachines.Add oWorkerMachine, sMachineName
  535.             With oWorkerMachine
  536.                 .Remote = True
  537.                 .MachineName = sMachineName
  538.             End With
  539.         End If
  540.         On Error GoTo SetWorkersOnMachineError
  541.         Set oWorkerProvider = oWorkerMachine.WorkerProvider
  542.     End If
  543.     
  544.     'Now see if more workers need destroyed on this machine
  545.     With oWorkerMachine
  546.         If .WorkerKeys.Count > lQuantityOnMachine Then
  547.             Do Until .WorkerKeys.Count <= lQuantityOnMachine
  548.                 'Find a worker on this machine
  549.                 lWorkerToRemove = .WorkerKeys.Item(1)
  550.                 .WorkerKeys.Remove 1
  551.                 'Remove the found worker
  552.                 'Do not destroy the Worker if it is busy
  553.                 'instead just flip its RemoveMe flag
  554.                 giWorkerCount = giWorkerCount - 1
  555.                 If gcWorkers.Item(CStr(lWorkerToRemove)).Busy Then
  556.                     gcWorkers.Item(CStr(lWorkerToRemove)).RemoveMe = True
  557.                 Else
  558.                     iRetry = 0
  559.                     gcWorkers.Item(CStr(lWorkerToRemove)).Worker.ShutDown
  560.                     Set gcWorkers.Item(CStr(lWorkerToRemove)).Worker = Nothing
  561.                     gcWorkers.Remove CStr(lWorkerToRemove)
  562.                 End If
  563.             Loop
  564.         Else
  565.             'Else lQuantityOnMachine must be greater than .WorkerKeys.count
  566.             'So add to the collection
  567.             bAddingWorker = True
  568.             Do Until .WorkerKeys.Count = lQuantityOnMachine
  569.                 'Choose a unique key
  570.                 lAdd = glLastKeyUsed + 1
  571.                 glLastKeyUsed = lAdd
  572.                 Set oWork = New clsWorker
  573.                 oWork.Busy = False
  574.                 'Get a new Worker object
  575.                 If bRemote Then
  576.                     Set oWork.Worker = oWorkerProvider.GetWorker
  577.                 Else
  578.                     Set oWork.Worker = New AEWorker.Worker
  579.                 End If
  580.                 'Set the WorkerID property of AEWorker.Worker
  581.                 'Set the new worker property to the properties
  582.                 'that have been set for the any other workers
  583.                 iRetry = 0
  584.                 oWork.Worker.SetProperties gbLogWorkers, gbEarlyBindServices, _
  585.                         gbPersistentServices, lAdd
  586.                 'Add the clsWorker class object which holds a
  587.                 'reference to the Worker class object to gcWorkers collection
  588.                 'Use the WorkerID as the key
  589.                 gcWorkers.Add oWork, CStr(lAdd)
  590.                 giWorkerCount = giWorkerCount + 1
  591.                 .WorkerKeys.Add lAdd
  592.                 iRetry = 0
  593.                 Set oWork.Worker.QueueMgrRef = New clsQueueDelegator
  594.                 oWork.Worker.StartPollingQueue
  595.             Loop
  596.             bAddingWorker = False
  597.         End If
  598.     End With
  599. SetWorkersOnMachineEnd:
  600.     'Update the WorkerCount label in the U/I
  601.     'Set connection settings back to local
  602.     iResult = oRacReg.SetAutoServerSettings(False, "AEWorkerProvider.WorkerProvider")
  603.     If iResult <> 0 Then GoTo SetWorkersOnMachine_RacRegError
  604.     
  605.     If gbShow Then
  606.         With frmQueueMgr.lblWorkerCount
  607.             .Caption = gcWorkers.Count
  608.             .Refresh
  609.         End With
  610.     End If
  611.     
  612.     'If the WorkerKeys.count = 0 and bRemote is true
  613.     'then the clsWorkerMachines class
  614.     'object in gcWorkerMachines should be removed
  615.     'Don't remove the clsWorkerMachines object representing the
  616.     'local machine.  Index one is reserved for the local machine.
  617.     If oWorkerMachine.WorkerKeys.Count = 0 And bRemote Then
  618.         On Error Resume Next
  619.         gcWorkerMachines.Remove sMachineName
  620.     End If
  621.     SetWorkersOnMachine = sErrors
  622.     Exit Function
  623.     
  624. SetWorkersOnMachine_RacRegError:
  625.     Err.Raise giCONNECTION_SETTING_FAILED
  626.     
  627. SetWorkersOnMachineError:
  628.     Select Case Err.Number
  629.         Case RPC_E_CALL_REJECTED
  630.             'Collision error, the OLE server is busy
  631.             Dim il As Integer
  632.             Dim ir As Integer
  633.             'First check for stop test
  634.             If iRetry < giMAX_ALLOWED_RETRIES Then
  635.                 iRetry = iRetry + 1
  636.                 ir = Int((giRETRY_WAIT_MAX - giRETRY_WAIT_MIN + 1) * Rnd + giRETRY_WAIT_MIN)
  637.                 For il = 0 To ir
  638.                     DoEvents
  639.                 Next il
  640.                 LogEvent giCALL_REJECTED_RETRY, 0
  641.                 Resume
  642.             Else
  643.                 'We reached our max retries
  644.                 GoTo SetWorkersOnMachineUnexpectedError
  645.             End If
  646.         Case ERR_CANT_FIND_KEY_IN_REGISTRY
  647.             'AEInstancer.Instancer is a work around for error
  648.             '-2147221166 which occurrs every time a client
  649.             'object creates an instance of a remote server,
  650.             'destroys it, registers it local, and tries to
  651.             'create a local instance.  The client can not
  652.             'create an object registered locally after it created
  653.             'an instance while it was registered remotely
  654.             'until it shuts down and restarts.  Therefore,
  655.             'it works to call another process to create the
  656.             'local instance and pass it back.
  657.             Dim oInstancer As AEInstancer.Instancer
  658.             Set oInstancer = New AEInstancer.Instancer
  659.             Set oWorkerProvider = oInstancer.Object("AEWorkerProvider.WorkerProvider")
  660.             Set oInstancer = Nothing
  661.             Resume Next
  662.         Case RPC_S_UNKNOWN_AUTHN_TYPE
  663.             'Tried to connect to a server that does not support
  664.             'specified authentication level.  Display message and
  665.             'switch to no authentication and try again
  666.             Dim s As String
  667.             s = sMachineName & gsSEPERATOR & LoadResString(giUSING_NO_AUTHENTICATION)
  668.             LogText s, 0
  669.             sErrors = s & vbCrLf
  670.             iResult = oRacReg.SetAutoServerSettings(True, "AEWorkerProvider.WorkerProvider", , sMachineName, gsProtocol, glAUTHENTICATION_DEFAULT)
  671.             Resume
  672.         Case ERR_OVER_FLOW
  673.             glLastKeyUsed = 0
  674.             Resume
  675.         Case ERR_DUPLICATE_KEY
  676.             'Assusmes on line "gcWorkers.Add oWork, cstr(lAdd)"
  677.             If lAdd = glMAX_ID Then lAdd = 0 Else lAdd = lAdd + 1
  678.             glLastKeyUsed = lAdd
  679.             oWork.ID = lAdd
  680.             Resume
  681.         Case giCONNECTION_SETTING_FAILED
  682.             sErrors = ReplaceString(LoadResString(giCONNECTION_SETTING_FAILED), gsNAME_TOKEN, LoadResString(giRACREG_ERROR_CODE_OFFSET + iResult))
  683.             Err.Raise giNO_WORKERS_CREATED, , sErrors & vbCrLf & LoadResString(giNO_WORKERS_CREATED)
  684.         Case Else
  685. SetWorkersOnMachineUnexpectedError:
  686.             'There are three cases to respond to if there is an unexpected error
  687.             '1- If the error occured while NOT adding a worker it most likely
  688.             '   occured while removing one.  Resume Next to insure that the worker
  689.             '   is removed from the workers collection.
  690.             '2- If we were adding a worker and the worker class was registered local
  691.             '   log the error, and add it to the sError string, but raise the
  692.             '   giNO_WORKERS_CREATED error, because the system has a critical problem
  693.             '   if a local worker can not be created.
  694.             '3- If we were adding a worker and the worker class was registered remote
  695.             '   log the error, and add it to the sError string.  Exit procedure so
  696.             '   that calling procedure can try creating workers on another machine
  697.             Dim sSource As String
  698.             sSource = Err.Source
  699.             sErrors = sErrors & sMachineName & gsSEPERATOR & sSource & gsSEPERATOR & Err.Description & vbCrLf
  700.             LogError Err, 0
  701.             If Not bAddingWorker Then
  702.                 Resume Next
  703.             Else
  704.                 If bRemote Then
  705.                     sErrors = sErrors & vbCrLf & ReplaceString(LoadResString(giCOULD_NOT_CREATE_WORKER_ON_MACHINE), gsNAME_TOKEN, sMachineName)
  706.                     Resume SetWorkersOnMachineEnd
  707.                 Else
  708.                     iResult = oRacReg.SetAutoServerSettings(False, "AEWorkerProvider.WorkerProvider")
  709.                     sErrors = sErrors & vbCrLf & LoadResString(giCOULD_NOT_CREATE_LOCAL_WORKER)
  710.                     Err.Raise giNO_WORKERS_CREATED, sSource, sErrors & vbCrLf & LoadResString(giNO_WORKERS_CREATED)
  711.                 End If
  712.             End If
  713.     End Select
  714. End Function
  715.